package me.minetsh.imaging.view;

import me.minetsh.imaging.view.stick.IMGStickerView;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.render.*;
import ohos.agp.text.SimpleTextLayout;
import ohos.agp.utils.*;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * IMGView
 *
 * @since 2021-07-27
 */
public class IMGView extends Image implements Component.TouchEventListener, Component.DrawTask {
    /**
     * 涂鸦路径
     */
    private List<IMGPath> mDoodles = new ArrayList<>();

    /**
     * 马赛克路径
     */
    private List<IMGPath> mMosaics = new ArrayList<>();

    /**
     * 为被选中贴片
     */
    private List<IMGStickerView> imgStickerViews = new ArrayList<>();

    /**
     * 完整图片边框
     */
    private RectFloat mFrame;

    private Paint mPaint;

    private Point mPrePoint = new Point();

    private Point mPreCtrlPoint = new Point();

    private PixelMap mImage, mMosaicImage;

    private Paint mMosaicPaint;

    private Canvas mCanvas;
    private Texture mTexture;
    private boolean isDrawPaint = false;
    private Color paintColor = Color.RED;

    private IMGMode mode;
    private IMGCallBack imgCallBack;

    /**
     * 绘制成功回调
     */
    interface IMGCallBack {
        /**
         * 绘制成功回调
         *
         * @param isComplete 是否完成
         */
        void drawComplete(boolean isComplete);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public IMGView(Context context) {
        super(context);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 属性
     */
    public IMGView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context   上下文
     * @param attrSet   属性
     * @param styleName 样式名
     */
    public IMGView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint();
        addDrawTask(this::onDraw);
        setTouchEventListener(this::onTouchEvent);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawPaintBg();

        //图片偏移
        float leftMar = getComponentWidth() == getImageWidth() ? 0 : (getComponentWidth() - getImageWidth()) / 2;
        float topMar = getComponentHeight() == getImageHeight() ? 0 : (getComponentHeight() - getImageHeight()) / 2;
        Matrix matrix = new Matrix();
        matrix.translate(-leftMar, -topMar);
        mCanvas.setMatrix(matrix);

        //绘制马赛克
        makeMosaicBitmap();
        onDrawMosaics(canvas);
        onDrawMosaics(mCanvas);

        //绘制涂鸦
        onDrawDoodles(canvas);
        onDrawDoodles(mCanvas);

        //绘制文字
        canvasDrawText(canvas);
        canvasDrawText(mCanvas);

        if (imgCallBack != null) {
            imgCallBack.drawComplete(true);
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN: {
                addPaint();
                MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());
                mPrePoint.position[0] = point.getX();
                mPrePoint.position[1] = point.getY();
                mPreCtrlPoint.position[0] = point.getX();
                mPreCtrlPoint.position[1] = point.getY();

                if (!isDoodleEmpty() && mode == IMGMode.DOODLE) {
                    mDoodles.get(mDoodles.size() - 1).getPath().moveTo(point.getX(), point.getY());
                }
                if (!ismMosaicsEmpty() && mode == IMGMode.MOSAIC) {
                    mMosaics.get(mMosaics.size() - 1).getPath().moveTo(point.getX(), point.getY());
                }
                return true;
            }
            case TouchEvent.PRIMARY_POINT_UP:
                break;
            case TouchEvent.POINT_MOVE: {
                MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());
                Point currCtrlPoint = new Point((point.getX() + mPrePoint.position[0]) / 2,
                        (point.getY() + mPrePoint.position[1]) / 2);
                if (!isDoodleEmpty() && mode == IMGMode.DOODLE) {
                    mDoodles.get(mDoodles.size() - 1).getPath().cubicTo(mPrePoint, mPreCtrlPoint, currCtrlPoint);
                }
                if (!ismMosaicsEmpty() && mode == IMGMode.MOSAIC) {
                    mMosaics.get(mMosaics.size() - 1).getPath().cubicTo(mPrePoint, mPreCtrlPoint, currCtrlPoint);
                }

                mPreCtrlPoint.position[0] = currCtrlPoint.position[0];
                mPreCtrlPoint.position[1] = currCtrlPoint.position[1];
                mPrePoint.position[0] = point.getX();
                mPrePoint.position[1] = point.getY();
                invalidate();
                break;
            }
        }
        return false;
    }

    /**
     * 撤销涂鸦
     */
    public void undoDoodle() {
        if (!mDoodles.isEmpty()) {
            mDoodles.remove(mDoodles.size() - 1);
            invalidate();
        }
    }

    /**
     * 撤销马赛克
     */
    public void undoMosaic() {
        if (!mMosaics.isEmpty()) {
            mMosaics.remove(mMosaics.size() - 1);
            invalidate();
        }
    }

    /**
     * 添加画笔
     */
    public void addPaint() {
        if (mode == IMGMode.DOODLE) {
            IMGPath imgPath = new IMGPath();
            imgPath.setPath(new Path());
            imgPath.setMode(IMGMode.DOODLE);
            imgPath.setColor(paintColor);
            imgPath.setWidth(45f);
            mDoodles.add(imgPath);
        } else if (mode == IMGMode.MOSAIC) {
            IMGPath imgPath = new IMGPath();
            imgPath.setPath(new Path());
            imgPath.setMode(IMGMode.MOSAIC);
            imgPath.setWidth(72f);
            mMosaics.add(imgPath);
        }

    }

    /**
     * 设置画笔颜色
     *
     * @param color Color
     */
    public void setPaintColor(Color color) {
        this.paintColor = color;
    }

    private void drawPaintBg() {
        mImage = getPixelMap();

        if (mImage != null) {
            mTexture = new Texture(createBitmap(getImageWidth(), getImageHeight()));
            mCanvas = new Canvas(mTexture);
            // 将图片缩放到屏幕宽度
            mCanvas.drawPixelMapHolderRect(new PixelMapHolder(this.mImage), new RectFloat(0,
                    0, getImageWidth(), getImageHeight()), new Paint());
            isDrawPaint = true;
        }
    }

    private void makeMosaicBitmap() {
        if (mMosaicImage != null || mImage == null) {
            return;
        }

        int w = Math.round(getImageWidth() / 64f);
        int h = Math.round(getImageHeight() / 64f);

        w = Math.max(w, 8);
        h = Math.max(h, 8);

        // 马赛克画刷
        if (mMosaicPaint == null) {
            mMosaicPaint = new Paint();
            mMosaicPaint.setFilterBitmap(false);
            mMosaicPaint.setBlendMode(BlendMode.SRC_IN);
        }

        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(w, h);
        initializationOptions.editable = true;
        mMosaicImage = PixelMap.create(mImage, initializationOptions);
    }

    private int onDrawMosaicsPath(Canvas canvas) {
        mImage = getPixelMap();
        if (mImage == null) {
            return 0;
        }

        float leftMar = (getComponentWidth() - getImageWidth()) == 0 ? 0 : (getComponentWidth() - getImageWidth()) / 2;
        float topMar = (getComponentHeight() - getImageHeight()) == 0 ? 0 : (getComponentHeight() - getImageHeight()) / 2;
        mFrame = new RectFloat(leftMar, topMar, getImageWidth() + leftMar, getImageHeight() + topMar);

        int layerCount = canvas.saveLayer(mFrame, new Paint());
        if (!ismMosaicsEmpty()) {
            canvas.save();
            for (IMGPath path : mMosaics) {
                path.onDrawMosaic(canvas, mPaint);
            }
            canvas.restore();
        }
        return layerCount;
    }

    private void onDrawMosaics(Canvas canvas) {
        int layerCount = onDrawMosaicsPath(canvas);
        canvas.drawPixelMapHolderRect(new PixelMapHolder(mMosaicImage), mFrame, mMosaicPaint);
        canvas.restoreToCount(layerCount);
    }

    private PixelMap createBitmap(int width, int height) {
        try {
            PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
            options.size = new Size(width, height);
            options.pixelFormat = PixelFormat.ARGB_8888;
            return PixelMap.create(options);
        } catch (OutOfMemoryError e) {
            return (PixelMap) Collections.emptyList();
        }
    }

    /**
     * getCurrentBitmap
     *
     * @return PixelMap
     */
    public PixelMap getCurrentBitmap() {
        if (mTexture == null) {
            drawPaintBg();
        }
        if (!isDrawPaint) {
            drawPaintBg();
        }
        return mTexture.getPixelMap();
    }

    private int getComponentWidth() {
        return getWidth();
    }

    private int getComponentHeight() {
        return getHeight();
    }

    private int getImageHeight() {
        double screenPer = (double) getComponentWidth() / (double) getComponentHeight();
        double per = (double) mImage.getImageInfo().size.width / (double) mImage.getImageInfo().size.height;
        if (screenPer >= per) {
            return getComponentHeight();
        } else {
            return (int) (getComponentWidth() / per);
        }
    }

    private int getImageWidth() {
        double screenPer = (double) getComponentWidth() / (double) getComponentHeight();
        double per = (double) mImage.getImageInfo().size.width / (double) mImage.getImageInfo().size.height;

        if (screenPer >= per) {
            return (int) (getComponentHeight() * per);
        } else {
            return getComponentWidth();
        }
    }

    private int getRealHeight() {
        DisplayManager displayManager = DisplayManager.getInstance();
        Display display = displayManager.getDefaultDisplay(getContext()).get();

        int screenWidth = display.getAttributes().width;
        int screenHeight = display.getAttributes().height;

        double screenPer = (double) screenWidth / (double) screenHeight;
        double per = (double) mImage.getImageInfo().size.width / (double) mImage.getImageInfo().size.height;
        if (screenPer >= per) {
            return screenHeight;
        } else {
            return (int) (screenWidth / per);
        }
    }

    private int getRealWidth() {
        DisplayManager displayManager = DisplayManager.getInstance();
        Display display = displayManager.getDefaultDisplay(getContext()).get();

        int screenWidth = display.getAttributes().width;
        int screenHeight = display.getAttributes().height;

        double screenPer = (double) screenWidth / (double) screenHeight;
        double per = (double) mImage.getImageInfo().size.width / (double) mImage.getImageInfo().size.height;

        if (screenPer >= per) {
            return (int) (screenHeight * per);
        } else {
            return screenWidth;
        }
    }

    /**
     * 设置是否可触摸
     *
     * @param canTouch 是否可触摸
     */
    public void setCanTouch(boolean canTouch) {
        if (canTouch) {
            this.setTouchEventListener(this::onTouchEvent);
        } else {
            this.setTouchEventListener(null);
        }
    }

    /**
     * 涂鸦
     *
     * @param canvas Canvas
     */
    public void onDrawDoodles(Canvas canvas) {
        if (!isDoodleEmpty()) {
            canvas.save();
            for (IMGPath path : mDoodles) {
                path.onDrawDoodle(canvas, mPaint);
            }
            canvas.restore();
        }
    }

    /**
     * 设置模式
     *
     * @param mode IMGMode
     */
    public void setIMGMode(IMGMode mode) {
        this.mode = mode;
    }

    /**
     * 涂鸦是否为空
     *
     * @return 涂鸦是否为空
     */
    public boolean isDoodleEmpty() {
        return mDoodles.isEmpty();
    }

    /**
     * 马赛克是否为空
     *
     * @return boolean
     */
    public boolean ismMosaicsEmpty() {
        return mMosaics.isEmpty();
    }

    /**
     * 绘制文字贴片
     *
     * @param stickerViews 文字贴片集合
     * @param imgCallBack 绘制回调
     */
    public void drawText(List<IMGStickerView> stickerViews, IMGCallBack imgCallBack) {
        this.imgCallBack = imgCallBack;
        this.imgStickerViews = stickerViews;
        invalidate();
    }

    /**
     * 删除文字贴片
     *
     * @param stickerView 文字贴片view
     */
    public void removeText(IMGStickerView stickerView) {
        imgStickerViews.remove(stickerView);
        invalidate();
    }

    private void canvasDrawText(Canvas canvas) {
        if (imgStickerViews.size() == 0) {
            return;
        }

        for (IMGStickerView imgStickerView : imgStickerViews) {
            canvas.save();

            //画文字
            Paint textPaint = new Paint();
            textPaint.setColor(imgStickerView.getStickerTextColor());
            textPaint.setTextSize((int) (70 * imgStickerView.getContentView().getScaleY()));
            textPaint.setStrokeWidth(30);
            textPaint.setMultipleLine(true);

            float centerX = imgStickerView.getComponentPosition().getCenterX();
            float centerY = imgStickerView.getComponentPosition().getCenterY();

            float leftMar = getComponentWidth() == getImageWidth() ? 0 : (getComponentWidth() - getImageWidth()) / 2;
            float topMar = getComponentHeight() == getImageHeight() ? 0 : (getComponentHeight() - getImageHeight()) / 2;
            float potX = centerX;
            float potY = centerY;

            Point point = new Point(potX + imgStickerView.getTranslationX() - (centerX - imgStickerView.getComponentPosition().left),
                    potY + imgStickerView.getTranslationY());
            textPaint.setPosition(point);

            Rect rect = new Rect(0, 0, getComponentWidth(), getComponentHeight());
            SimpleTextLayout textLayout = new SimpleTextLayout(imgStickerView.getStickerText(), textPaint, rect, getComponentWidth());

            if (imgStickerView.getRotation() != 0) {
                Matrix matrix = new Matrix();
                matrix.setRotate(imgStickerView.getRotation(), (potX + imgStickerView.getTranslationX() - leftMar),
                        potY + imgStickerView.getTranslationY() + (centerY - imgStickerView.getComponentPosition().top));
                canvas.setMatrix(matrix);
            }
            textLayout.drawText(canvas);
            canvas.restore();
        }
    }
}
